﻿#pragma once

#include "PBaseCommon.h"

//  | * | * | * | * | * | * | * | * |   |
//   x0                              x1

class PRegion;
typedef PLinklist<PRegion> PRegionList;

class PAreaItem
{
public:
	PAreaItem():x(0.0),y(0.0),area(0.0)
	{
	}
	PAreaItem(double _x,double _y,double _a):x(_x),y(_y),area(_a)
	{
	}
	double x,y;//中心
	double area;//面积
};

class PMatRegion//图像区域 矩阵区域 二值表示 0 or 255
{
public:
	PMatRegion():_width(0),_height(0),_data(0) {}
	PMatRegion(const PMatRegion &p);
	PMatRegion(int w,int h);
	~PMatRegion();
	void reset(int w,int h);
	void reset(int w,int h,const byte *p);
	PMatRegion & operator=(const PMatRegion &p);
	inline byte at(int x,int y) const
	{
		return _data[(y+1)*(_width+2)+x+1];
	}
	inline byte & at(int x,int y)
	{
		return _data[(y + 1) *(_width+2)+x+1];
	}
	inline byte operator()(int x,int y) const
	{
		return _data[(y + 1) *(_width+2)+x+1];
	}
	inline byte & operator()(int x,int y)
	{
		return _data[(y + 1) *(_width+2)+x+1];
	}
	inline int width() const
	{
		return _width;
	}
	inline int height() const
	{
		return _height;
	}
	inline const byte * row(int r) const
	{
		return _data+(r+1)*(_width+2)+1;
	}
	//inline const byte * data() const
	//{
	//	return _data;
	//}
	inline byte * row(int r)
	{
		return _data+(r+1)*(_width+2)+1;
	}
	//inline byte * data()
	//{
	//	return _data;
	//}
	inline int area()
	{
		return _height*_width;
	}
	PRegion threshold(const PRect& rect);
	PRegion threshold();
	void thinning();//二值区域细化
	void thinning(const PRegion & roi);//二值区域细化
	void connect(PLinklist<PPointset> &plist,int len_min = 8);//细化的二值区域转为有序点集
	void cutdown(const PRegion& roi);
protected:
	void clearFlag(const PRegion & roi);
	byte* _data;
	int _width;
	int _height;
};

class PRegionLine;//行的行程

class PRegionPos
{
public:
	PRegionPos(PRegionLine * pos):x(0),line(pos) {}
	PRegionLine *line;
	int x;
};

class PRegionItem//单个行程
{
public:
	PRegionItem():x0(0),x1(0),y(0) {}
	PRegionItem(int _y):x0(0),x1(0),y(_y) {}
	PRegionItem(int _y,int _x0,int _x1):x0(_x0),x1(_x1),y(_y) {}
	PRegionItem(const PRegionItem &p)
	{
		y=p.y;
		x0=p.x0;
		x1=p.x1;
	}
	int y;
	int x0,x1;//x0<=x<x1
	inline PRegionItem & operator=(const PRegionItem &p)
	{
		y=p.y;
		x0=p.x0;
		x1=p.x1;
		return (*this);
	}
	inline bool operator<(const PRegionItem &p)
	{
		if(y==p.y) return x0<p.x0;
		else return y<p.y;
	}
	inline bool operator==(const PRegionItem &p)
	{
		return y==p.y && x0==p.x0 && x1==p.x1;
	}
	//inline bool adjacent(const PRegionItem &p)//相邻,8连通
	//{
	//	if(p.y<y-1 || p.y>y+1) return false;
	//	else if(p.x1<x0 || p.x0>x1) return false;
	//	else return true;
	//}
	inline bool adjacent(int _x0,int _x1)//相邻,8连通
	{
		if(_x1<x0 || _x0>x1) return false;
		else return true;
	}
	inline bool _adjacent(int _x0,int _x1)//相邻,4连通
	{
		if(_x1<=x0 || _x0>=x1) return false;
		else return true;
	}
	inline int length()
	{
		return x1-x0;
	}
};

class PRegion
{
public:
	PRegion();
	PRegion(const PRegion &t);
	~PRegion();
	PRegion copy() const;
	void clear();
	PRegionLine * begin() const;
	PRegionLine * end() const;
	void offset(int x,int y);
	bool isEmpty() const;
	bool noEmpty() const;
	void insert(int y,int x0,int x1);//插入一个行程
	inline void insert(const PRegionItem &p)
	{
		insert(p.y,p.x0,p.x1);
	}
	PRegion& operator+=(const PRegion& t);
	PRegion& operator-=(const PRegion& t);
	inline PRegion operator+(const PRegion &t) const
	{
		return merge(t);
	}
	inline PRegion operator-(const PRegion &t) const
	{
		return subtract(t);
	}
	PRegion & operator=(const PRegion &t);
	inline bool contain(int x,int y) const;
	inline bool contain(const PPoint &p) const;
	void pointset(PPointset &pset) const;
	double area() const;
	PAreaItem areaCenter() const ;//返回0，表示未求出形心
	PEllipse2 ellipticAxis() const;
	void buildEllipse(int x,int y,int a,int b);
	void buildEllipse(const PEllipse2 &ellipse);
	void buildCircle(const PCircle &circle);
	void buildCircleSE(int d);//d 直径
	void buildSquareSE(int d);//d 边长，正方形
	void buildRectangleSE(int d1,int d2);//d1 长,d2 宽
	void buildRhombusSE(int d);//d 中径长
	void buildCircleRim(const PCircle &circle,double w);//圆环区域
	void buildRectangle(int x1,int y1,int x2,int y2);
	void buildRectangle(const PRectangle2 &rect);
	void buildPolygon(const PPolygon &polygon);
	PRect boundRectangle() const;//外接矩形,边平行坐标轴
	PRectangle2 boundRectangle(const PSLine &line) const;//外接矩形,边平行给定直线
	int ymin(int x) const;
	int ymax(int x) const;
	PPair yrange(int x) const;
	void connection(PRegionList& plist);
	void connection(PRegionList& plist) const;
	PRegion connection();//获得一个连通区域,可连续调用直到获得所有区域
	PCircle leastSquareCircle() const;//最小二乘圆
	PSLine leastSquareLine() const;//最小二乘直线
	PCircle leastCircle() const;//最小外接圆
	PRectangle2 leastRectangle() const;//最小外接矩形
	inline PSLine ransacLine(double deviation) const
	{
		PPointset p;
		pointset(p);
		return p.ransacLine(deviation);
	}
	inline PCircle ransacCircle(double deviation) const
	{
		PPointset p;
		pointset(p);
		return p.ransacCircle(deviation);
	}
	void convexHull(PPointset &polygon) const;//凸壳
	void contour(PLinklist<PPointset> &edges) const;//轮廓
	double contourLength() const;//轮廓长度
	//void border();//内边界 self
	PRegion border() const;//内边界
	PRegion thinning() const;//细化
	void holes(PRegionList &plist) const;
	PRegion hole() const;
	PRegion fullHoles() const;
	PRegion zoom(const PDPoint &ratio) const;
	PRegion transpose() const;//转置
	PRegion minkowskiAdd(const PRegion &element) const;
	PRegion minkowskiSub(const PRegion &element) const;
	PRegion dilation(const PRegion &element) const;//膨胀
	PRegion erosion(const PRegion &element) const;//腐蚀
	PRegion opening(const PRegion &element) const;//开操作
	PRegion closing(const PRegion &element) const;//闭操作
	PRegion hitMiss(const PRegion &e1,const PRegion &e2) const;//击中击不中变换
	PRegion merge(const PRegion &t) const;//并集
	PRegion intersection(const PRegion &t) const;//交集
	PRegion subtract(const PRegion &region) const;//差集,减去
	bool getRange(PRegionPos &pos,PRegionItem &item) const;
	void append(int y,int x0,int x1);
	void split(PRegion pout[],int num);//按行将区域(近似平均)拆分成多个
	bool save(const wchar_t* filename) const;
	bool read(const wchar_t* filename);
protected:
	void appendLine(PRegionLine *line);
	void prependLine(PRegionLine *line);
	void insertLineAfter(PRegionLine *pos,PRegionLine *line);//在pos之后插入行
	void insertLineBefore(PRegionLine *pos,PRegionLine *line);//在pos之前插入行
	void removeLine(PRegionLine *line);//移除并销毁一行
	void leaveLine(PRegionLine *line);//移除一行(不销毁)
	PRegion complement0() const;//补集
	void complement1();//补集
	void removeFirstConnect();
	void trim();
	PRegionLine * head;
	PRegionLine * tail;
	PRegionLine * current;
	int* ref;
};


